package com.sunwayworld.basemodule.samplemanage.sample.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.deepoove.poi.config.ConfigureBuilder;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.sunwayworld.basemodule.basedata.exporttemplate.bean.LimsExportTemplateBean;
import com.sunwayworld.basemodule.basedata.exporttemplate.service.LimsExportTemplateService;
import com.sunwayworld.basemodule.business.batch.bean.LimsBatchSampleProductBean;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchSampleProductService;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchSampleService;
import com.sunwayworld.basemodule.business.pjtask.service.LimsPjFolderService;
import com.sunwayworld.basemodule.business.prefolder.service.LimsPreFolderService;
import com.sunwayworld.basemodule.common.auditrecord.service.LimsAuditRecordService;
import com.sunwayworld.basemodule.common.utils.ExportUtil;
import com.sunwayworld.basemodule.common.utils.QRPicUtil;
import com.sunwayworld.basemodule.coredata.product.bean.LimsProductMainBean;
import com.sunwayworld.basemodule.coredata.product.service.LimsProductMainService;
import com.sunwayworld.basemodule.samplemanage.sample.bean.BatchSampleStaticsDTO;
import com.sunwayworld.basemodule.samplemanage.sample.bean.LimsSampleBean;
import com.sunwayworld.basemodule.samplemanage.sample.bean.LimsSampleDerivativeBean;
import com.sunwayworld.basemodule.samplemanage.sample.bean.SampleTreeDTO;
import com.sunwayworld.basemodule.samplemanage.sample.dao.LimsSampleDao;
import com.sunwayworld.basemodule.samplemanage.sample.dto.LimsBarCodeDTO;
import com.sunwayworld.basemodule.samplemanage.sample.dto.LimsSampleTagDTO;
import com.sunwayworld.basemodule.samplemanage.sample.service.LimsCourierService;
import com.sunwayworld.basemodule.samplemanage.sample.service.LimsSampleDerivativeService;
import com.sunwayworld.basemodule.samplemanage.sample.service.LimsSampleService;
import com.sunwayworld.basemodule.samplemanage.samplecodegenerate.bean.LimsSamplecodeGenerateRecordBean;
import com.sunwayworld.basemodule.samplemanage.samplecodegenerate.service.LimsSamplecodeGenerateRecordService;
import com.sunwayworld.basemodule.samplemanage.samplehandle.bean.LimsSampleHandleBean;
import com.sunwayworld.basemodule.samplemanage.samplehandle.bean.LimsSampleHandleRelationBean;
import com.sunwayworld.basemodule.samplemanage.samplehandle.service.LimsSampleHandleRelationService;
import com.sunwayworld.basemodule.samplemanage.samplehandle.service.LimsSampleHandleService;
import com.sunwayworld.cloud.module.item.calendar.bean.CoreCalendarBean;
import com.sunwayworld.cloud.module.item.calendar.service.CoreCalendarService;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.beans.BeanPropertyDescriptor;
import com.sunwayworld.framework.beans.BeanPropertyHelper;
import com.sunwayworld.framework.constant.Constant;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.context.LocalContextHelper;
import com.sunwayworld.framework.context.concurrent.GikamConcurrentLocker;
import com.sunwayworld.framework.data.CaseInsensitiveLinkedMap;
import com.sunwayworld.framework.data.page.Page;
import com.sunwayworld.framework.database.sql.Order;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.executor.ExecutorHelper;
import com.sunwayworld.framework.i18n.I18nHelper;
import com.sunwayworld.framework.io.file.FilePathDTO;
import com.sunwayworld.framework.io.file.FilePathManager;
import com.sunwayworld.framework.io.file.FileScope;
import com.sunwayworld.framework.mybatis.mapper.MapperParameter;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.mybatis.page.PageRowBounds;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.restful.data.RestValidationResultBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.support.PersistableHelper;
import com.sunwayworld.framework.support.tree.TreeDescriptor;
import com.sunwayworld.framework.support.tree.TreeHelper;
import com.sunwayworld.framework.utils.*;
import com.sunwayworld.module.item.file.bean.CoreFileBean;
import com.sunwayworld.module.item.file.bean.CoreFileLogBean;
import com.sunwayworld.module.item.file.manager.CoreFileManager;
import com.sunwayworld.module.item.file.service.CoreFileLogService;
import com.sunwayworld.module.item.file.service.CoreFileService;
import com.sunwayworld.module.item.file.utils.CoreFileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Repository
@GikamBean
public class LimsSampleServiceImpl implements LimsSampleService {

    private static final Logger logger = LogManager.getLogger(LimsSampleServiceImpl.class);

    // 二维码颜色
    private static final int BLACK = 0xFF000000;
    // 二维码颜色
    private static final int WHITE = 0xFFFFFFFF;

    @Autowired
    private LimsSampleDao limsSampleDao;

    @Autowired
    private LimsAuditRecordService auditRecordService;

    @Lazy
    @Autowired
    private CoreFileService coreFileService;

    @Lazy
    @Autowired
    private CoreFileManager coreFileManager;

    @Lazy
    @Autowired
    private LimsSampleHandleService sampleHandleService;

    @Lazy
    @Autowired
    private LimsSampleHandleRelationService relationService;

    @Lazy
    @Autowired
    private LimsBatchSampleProductService sampleProductService;

    @Autowired
    @Lazy
    private LimsSampleDerivativeService sampleDerivativeService;

    @Lazy
    @Autowired
    private LimsPreFolderService preFolderService;

    @Lazy
    @Autowired
    private LimsPjFolderService pjFolderService;

    @Lazy
    @Autowired
    private LimsExportTemplateService exportTemplateService;

    @Autowired
    @Lazy
    private CoreFileLogService coreFileLogService;

    @Autowired
    @Lazy
    private LimsCourierService limsCourierService;

    @Autowired
    @Lazy
    private LimsSamplecodeGenerateRecordService limsSamplecodeGenerateRecordService;

    @Autowired
    @Lazy
    private LimsProductMainService limsProductMainService;

    @Autowired
    @Lazy
    private CoreCalendarService coreCalendarService;

    @Autowired
    @Lazy
    private LimsBatchSampleService limsBatchSampleService;

    @Override
    @SuppressWarnings("unchecked")
    public LimsSampleDao getDao() {
        return limsSampleDao;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insert(RestJsonWrapperBean jsonWrapper) {
        LimsSampleBean limsSample = jsonWrapper.parseUnique(LimsSampleBean.class);
        limsSample.setId(ApplicationContextHelper.getNextIdentity());
        getDao().insert(limsSample);
        return limsSample.getId();
    }

    @Transactional
    @Override
    public void delete(RestJsonWrapperBean wrapper) {
        // 前端传完整的数据
        List<LimsSampleBean> deleteList = wrapper.parse(LimsSampleBean.class);
        if (deleteList.isEmpty()) return;
        getDao().deleteBy(deleteList);
    }

    @Transactional
    @Override
    public void back(RestJsonWrapperBean wrapperBean) {
        List<LimsSampleBean> parse = wrapperBean.parse(LimsSampleBean.class);
        String backRemark = wrapperBean.getParamValue("backRemark");
        String handleType = "back";
        LimsSampleHandleBean handleBean = new LimsSampleHandleBean();
        Long handleId = ApplicationContextHelper.getNextIdentity();
        handleBean.setId(handleId);
        handleBean.setHandleCode(ApplicationContextHelper.getNextSequence(getDao().getTable(), "H"));
        handleBean.setHandleType(handleType);
        handleBean.setRemark(backRemark);
        sampleHandleService.getDao().insert(handleBean);

        List<LimsSampleHandleRelationBean> relationBeans = new ArrayList<>();
        parse.forEach(s -> {
            s.setSampleHandleId(handleId);
            s.setInHandle(Constant.YES);
            s.setHandleType(handleType);
            s.setStatus("stop"); // 返样样本流程状态也变终止

            LimsSampleHandleRelationBean relationBean = new LimsSampleHandleRelationBean();
            relationBean.setId(ApplicationContextHelper.getNextIdentity());
            relationBean.setHandleId(handleId);
            relationBean.setSampleId(s.getId());
            relationBeans.add(relationBean);
        });

        relationService.getDao().insert(relationBeans);
        getDao().update(parse, "sampleHandleId", "inHandle", "handleType", "status", "hasHandle", "handleTime", "backRemark", "backExceptionHandle");
        List<Long> ids = parse.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(ids, "T_LIMS_SAMPLE", I18nHelper.getMessage("CORE.MENU.MENUNAME.SAMPLE_ABNORMAL_B"), I18nHelper.getMessage("GIKAM.BUTTON.SAMPLE_BACK"), backRemark);

    }

    @Override
    public void destroy(RestJsonWrapperBean wrapperBean) {
        List<LimsSampleBean> parse = wrapperBean.parse(LimsSampleBean.class);
        String backRemark = wrapperBean.getParamValue("backRemark");
        String handleType = "destroy";
        LimsSampleHandleBean handleBean = new LimsSampleHandleBean();
        Long handleId = ApplicationContextHelper.getNextIdentity();
        handleBean.setId(handleId);
        handleBean.setHandleCode(ApplicationContextHelper.getNextSequence(getDao().getTable(), "H"));
        handleBean.setHandleType(handleType);
        handleBean.setRemark(backRemark);
        sampleHandleService.getDao().insert(handleBean);

        List<LimsSampleHandleRelationBean> relationBeans = new ArrayList<>();
        parse.forEach(s -> {
            s.setSampleHandleId(handleId);
            s.setInHandle(Constant.YES);
            s.setHandleType(handleType);
            s.setStatus("stop"); // 销毁样本流程状态也变终止

            LimsSampleHandleRelationBean relationBean = new LimsSampleHandleRelationBean();
            relationBean.setId(ApplicationContextHelper.getNextIdentity());
            relationBean.setHandleId(handleId);
            relationBean.setSampleId(s.getId());
            relationBeans.add(relationBean);
        });
        relationService.getDao().insert(relationBeans);

        getDao().update(parse, "sampleHandleId", "inHandle", "handleType", "status", "hasHandle", "handleTime", "backRemark", "backExceptionHandle");
        List<Long> ids = parse.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(ids, "T_LIMS_SAMPLE", I18nHelper.getMessage("CORE.MENU.MENUNAME.SAMPLE_ABNORMAL_B"), I18nHelper.getMessage("GIKAM.BUTTON.SAMPLE_DESTROY"), backRemark);
    }

    // 查询流转单下的样本
    @Override
    public Page<LimsSampleBean> selectHandleSample(Long handleId, RestJsonWrapperBean wrapper) {
        MapperParameter mapperParameter = wrapper.extractMapFilter();
        mapperParameter.put("handleId", handleId);
        PageRowBounds pageRowBounds = wrapper.extractPageRowBounds();
        return selectPagination(() -> getDao().selectHandleSample(mapperParameter), pageRowBounds);
    }

    // 通过处置单查其下样本
    @Override
    public List<LimsSampleBean> selectHandleSample(Long handleId) {
        MapperParameter mapperParameter = new MapperParameter();
        mapperParameter.put("handleId", handleId);
        return getDao().selectHandleSample(mapperParameter).parallelStream().map(e -> PersistableHelper.mapToPersistable(e, LimsSampleBean.class)).collect(Collectors.toList());
    }

    @Override
    public Page<LimsSampleBean> selectExpiredSamples(RestJsonWrapperBean wrapperBean) {
        MapperParameter parameter = wrapperBean.extractMapFilter();
        PageRowBounds pageRowBounds = wrapperBean.extractPageRowBounds();
        return this.selectPagination(() -> getDao().selectExpiredSamples(parameter), pageRowBounds);
    }

    @Override
    public LimsSampleBean selectDetail(Long id) {
        Map<String, Object> map = getDao().selectDetail(id);
        return map != null && !map.isEmpty() ? PersistableHelper.mapToPersistable(map, LimsSampleBean.class) : null;
    }

    @Override
    @Transactional
    public JSONObject confirmSampleExpired(RestJsonWrapperBean jsonWrapperBean) {
        JSONObject req = new JSONObject();

        List<LimsSampleBean> updates = jsonWrapperBean.parse(LimsSampleBean.class);
        List<Long> ids = updates.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        LimsSampleBean updateBean = new LimsSampleBean();
        updateBean.setExpireFlg("1");
        getDao().updateByIds(updateBean, ids, "expireFlg");
        return req;
    }

    @Override
    public JSONObject receiveSampleWarp(RestJsonWrapperBean jsonWrapperBean) {
        JSONObject req = new JSONObject();

        String ids = jsonWrapperBean.getParamValue("ids");
        List<Long> sampleIds = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
        LimsSampleBean updateBean = jsonWrapperBean.parseUnique(LimsSampleBean.class);
        String[] updateColumns = new String[]{"warpStatus", "sampleStatus", "receiveAbnomalType", "receiveAbnomalRemark"};
        this.getDao().updateByIds(updateBean, sampleIds, updateColumns);
        return req;
    }

    @Override
    public JSONObject editSampleMulti(RestJsonWrapperBean jsonWrapperBean) {
        JSONObject req = new JSONObject();

        String ids = jsonWrapperBean.getParamValue("ids");
        String updateColumns = jsonWrapperBean.getParamValue("updateColumns");

        List<Long> sampleIds = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());

        List<LimsSampleBean> updateBeans = jsonWrapperBean.parse(LimsSampleBean.class);
        LimsSampleBean updateBean = updateBeans.get(0);
        getDao().updateByIds(updateBean, sampleIds, updateColumns.split(","));

        return req;
    }

    @Override
    public JSONObject saveAbnormalHandle(RestJsonWrapperBean jsonWrapperBean) {
        JSONObject req = new JSONObject();

//        String exceptionHandle = jsonWrapperBean.getParamValue("exceptionHandle");
//        String handleRemark = jsonWrapperBean.getParamValue("handleRemark");

        List<LimsSampleBean> sampleBeans = jsonWrapperBean.parse(LimsSampleBean.class);
        List<Long> sampleIds = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        LimsSampleBean updateBean = new LimsSampleBean();
        //updateBean.setExceptionHandle(exceptionHandle);
        //updateBean.setHandleRemark(handleRemark);

        getDao().updateByIds(updateBean, sampleIds, "exceptionHandle", "handleRemark");
        return req;
    }

    @Override
    public List<LimsSampleBean> selectForFormula(List<Long> ids) {
        MapperParameter mapperParameter = new MapperParameter();
        mapperParameter.put("ids", StringUtils.join(ids, ","));
        return getDao().selectForFormula(mapperParameter).parallelStream().map(m -> PersistableHelper.mapToPersistable(m, LimsSampleBean.class))
                .collect(Collectors.toList());
    }

    @Override
    public Page<LimsSampleBean> selectForFormula(RestJsonWrapperBean wrapper) {
        return selectPagination(() -> getDao().selectForFormula(wrapper.extractMapFilter()), wrapper.extractPageRowBounds());
    }

    @Override
    public Page<LimsSampleBean> selectByParams(RestJsonWrapperBean wrapper) {
        return selectPagination(() -> getDao().selectByParams(wrapper.extractMapFilter()), wrapper.extractPageRowBounds());
    }

    @Override
    @Transactional
    public Long printSampleTag(RestJsonWrapperBean wrapper) {
        List<LimsSampleBean> sampleBeans = wrapper.parse(LimsSampleBean.class);
        if (sampleBeans.isEmpty()) return 1L;

        List<Long> ids = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        sampleBeans = this.selectListByFilter(SearchFilter.instance().match("id", ids).filter(MatchPattern.OR));
        List<LimsSampleBean> finalSampleBeans = sampleBeans;

        LimsExportTemplateBean printTemplate = exportTemplateService.selectByTemplateCode("SampleCodePrintTemplate");
        Long id = null;
        if (ObjectUtils.isEmpty(printTemplate) || ObjectUtils.isEmpty(printTemplate.getTemplateFileId())) {
            FilePathDTO filePath = FilePathDTO.of(FileScope.temp.name(), "" + System.currentTimeMillis(), UUID.randomUUID().toString(), "样本标签.docx");
            Path path = FilePathManager.getLocalPath(filePath);
            try {
                FileUtils.makeDirs(path);
                URL resource = this.getClass().getResource("");
                if (FileUtils.isInJarURL(resource)) {
                    InputStream is = this.getClass().getResourceAsStream("templates/SampleCodePrintTemplate.docx");
                    Files.copy(is, path, new CopyOption[]{StandardCopyOption.REPLACE_EXISTING});
                } else {
                    Path templatePath = (new File(resource.getPath())).toPath().resolve("templates").resolve("SampleCodePrintTemplate.docx");
                    Files.copy(templatePath, path, StandardCopyOption.REPLACE_EXISTING);
                }
                if (ObjectUtils.isEmpty(printTemplate)) {
                    LimsExportTemplateBean entity = new LimsExportTemplateBean();
                    entity.setId(ApplicationContextHelper.getNextIdentity());
                    entity.setTemplateCode("SampleCodePrintTemplate");
                    entity.setFileName("SampleCodePrintTemplate.docx");
                    entity.setTemplateName("样本标签打印");
                    entity.setTemplateFileId(ApplicationContextHelper.getNextIdentity());
                    id = entity.getTemplateFileId();
                    exportTemplateService.getDao().insert(entity);
                } else if (ObjectUtils.isEmpty(printTemplate.getTemplateFileId())) {
                    printTemplate.setTemplateFileId(ApplicationContextHelper.getNextIdentity());
                    printTemplate.setFileName("SampleCodePrintTemplate.docx");
                    id = printTemplate.getTemplateFileId();
                    exportTemplateService.getDao().update(printTemplate, "FileName", "templateFileId");
                }

                CoreFileBean coreFileBean = new CoreFileBean();
                coreFileBean.setId(id);
                coreFileBean.setTargetId("T_LIMS_EXPORT_TEMPLATE$" + id);
                coreFileBean.setName("SampleCodePrintTemplate.docx");
                coreFileBean.setFileExt(FileUtils.getFileExtension(coreFileBean.getName()));
                coreFileBean.setMd5Name(EncryptUtils.MD5Encrypt(coreFileBean.getId() + "$" + coreFileBean.getName()));
                coreFileBean.setScope(FileScope.temp.name());
                coreFileBean.setSize(path.toFile().length());
                coreFileBean.setTimes(0L);
                coreFileBean.setExt("docx");
                coreFileBean.setDownloadable("1");
                coreFileBean.setCreatedTime(LocalDateTime.now());
                coreFileService.getDao().insert(coreFileBean);
                coreFileManager.upload(coreFileBean, path.toFile());
                try (InputStream in = new FileInputStream(path.toFile()); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                    ExportUtil.build(in, builder -> buildSampleTagParams(builder, finalSampleBeans), os);

                    CoreFileBean qrCodeFile = new CoreFileBean();
                    BeanUtils.copyProperties(coreFileBean, qrCodeFile, "id", "targetId", "Md5Name", "size");
                    qrCodeFile.setId(ApplicationContextHelper.getNextIdentity());
                    qrCodeFile.setTargetId("T_LIMS_SAMPLE_BARCODE$" + StringUtils.randomUUID());
                    qrCodeFile.setSize((long) os.size());
                    qrCodeFile.setMd5Name(EncryptUtils.MD5Encrypt(qrCodeFile.getId() + "$" + qrCodeFile.getName()));
                    try (ByteArrayInputStream temp = new ByteArrayInputStream(os.toByteArray())) {
                        coreFileManager.upload(qrCodeFile, temp);
                    }
                    id = qrCodeFile.getId();
                }
            } catch (Exception e1) {
                throw new InvalidDataException(I18nHelper.getMessage("THE.SAMPLE.LABEL.TEMPLATE.IS.NOT.MAINTAINED"));
            }
        } else {
            CoreFileBean coreFileBean = coreFileService.selectById(printTemplate.getTemplateFileId());
            File file = CoreFileUtils.getLocalPath(coreFileBean).toFile();
            if (!file.exists()) {
                FilePathDTO filePath = FilePathDTO.of(FileScope.temp.name(), "" + System.currentTimeMillis(), UUID.randomUUID().toString(), "样本标签.docx");
                Path path = FilePathManager.getLocalPath(filePath);
                try {
                    FileUtils.makeDirs(path);
                    URL resource = this.getClass().getResource("");
                    if (FileUtils.isInJarURL(resource)) {
                        InputStream is = this.getClass().getResourceAsStream("templates/SampleCodePrintTemplate.docx");
                        Files.copy(is, path, new CopyOption[]{StandardCopyOption.REPLACE_EXISTING});
                    } else {
                        Path templatePath = (new File(resource.getPath())).toPath().resolve("templates").resolve("SampleCodePrintTemplate.docx");
                        Files.copy(templatePath, path, StandardCopyOption.REPLACE_EXISTING);
                    }

                    coreFileBean.setSize(path.toFile().length());
                    coreFileBean.setCreatedTime(LocalDateTime.now());
                    coreFileService.getDao().update(coreFileBean, "createdTime", "size");
                    coreFileManager.upload(coreFileBean, path.toFile());
                    try (InputStream in = new FileInputStream(path.toFile()); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                        ExportUtil.build(in, builder -> buildSampleTagParams(builder, finalSampleBeans), os);

                        CoreFileBean qrCodeFile = new CoreFileBean();
                        BeanUtils.copyProperties(coreFileBean, qrCodeFile, "id", "targetId", "Md5Name", "size");
                        qrCodeFile.setId(ApplicationContextHelper.getNextIdentity());
                        qrCodeFile.setTargetId("T_LIMS_SAMPLE_BARCODE$" + StringUtils.randomUUID());
                        qrCodeFile.setSize((long) os.size());
                        qrCodeFile.setMd5Name(EncryptUtils.MD5Encrypt(qrCodeFile.getId() + "$" + qrCodeFile.getName()));
                        coreFileManager.upload(qrCodeFile, new ByteArrayInputStream(os.toByteArray()));

                        id = qrCodeFile.getId();
                    }
                } catch (Exception e2) {
                    throw new InvalidDataException(I18nHelper.getMessage("THE.SAMPLE.LABEL.TEMPLATE.IS.NOT.MAINTAINED"));
                }
            } else {
                try (InputStream in = new FileInputStream(file); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                    ExportUtil.build(in, builder -> buildSampleTagParams(builder, finalSampleBeans), os);

                    CoreFileBean insertFileBean = new CoreFileBean();
                    insertFileBean.setId(ApplicationContextHelper.getNextIdentity());
                    insertFileBean.setTargetId("T_LIMS_SAMPLE_BARCODE$" + StringUtils.randomUUID());
                    insertFileBean.setName("样本标签.docx");
                    insertFileBean.setFileExt(FileUtils.getFileExtension(insertFileBean.getName()));
                    insertFileBean.setMd5Name(EncryptUtils.MD5Encrypt(insertFileBean.getId() + "$" + insertFileBean.getName()));
                    insertFileBean.setScope(FileScope.secure.name());
                    insertFileBean.setSize((long) os.size());
                    insertFileBean.setTimes(0L);
                    insertFileBean.setExt("docx");
                    insertFileBean.setDownloadable("1");
                    insertFileBean.setCreatedTime(LocalDateTime.now());
                    coreFileService.getDao().insert(insertFileBean);
                    try (ByteArrayInputStream temp = new ByteArrayInputStream(os.toByteArray())) {
                        coreFileManager.upload(insertFileBean, temp);
                    }
                    id = insertFileBean.getId();
                } catch (Exception e3) {
                    throw new InvalidDataException(I18nHelper.getMessage("THE.SAMPLE.LABEL.TEMPLATE.IS.NOT.MAINTAINED"));
                }
            }
        }

        return id;
    }

    private LimsSampleTagDTO buildSampleTagParams(ConfigureBuilder builder, List<LimsSampleBean> limsSampleBeans) {
        LimsSampleTagDTO sampleTagDTO = new LimsSampleTagDTO();
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        List<LimsBarCodeDTO> barCodeDTOList = new ArrayList<>();
        int qrCodeSize = 400;
        String temp = ApplicationContextHelper.getConstantValue("qrCodeSize");
        if (!StringUtils.isBlank(temp)) {
            try {
                qrCodeSize = Integer.parseInt(temp);
            } catch (Exception e) {

            }
        }
        for (LimsSampleBean limsSampleBean : limsSampleBeans) {
            LimsBarCodeDTO limsBarCodeDTO = new LimsBarCodeDTO();
            limsBarCodeDTO.setSampleCode(limsSampleBean.getSampleCode());
            limsBarCodeDTO.setSampleName(limsSampleBean.getSampleName());
            limsBarCodeDTO.setBatchCode(limsSampleBean.getExt$Item("batchcode"));
            limsBarCodeDTO.setBoard(limsSampleBean.getLocations());
            limsBarCodeDTO.setBarcode(QRPicUtil.generateQrCodeImg(limsSampleBean.getSampleCode(), qrCodeSize, qrCodeSize));
            limsBarCodeDTO.setDate(date);

            limsBarCodeDTO.setCodeFront(limsSampleBean.getSampleCode().substring(0, 7));
            limsBarCodeDTO.setCodeBack(limsSampleBean.getSampleCode().substring(7));
            int barCodeSize = 50;
            String temp2 = ApplicationContextHelper.getConstantValue("barCodeSize");
            if (!StringUtils.isBlank(temp2)) {
                try {
                    barCodeSize = Integer.parseInt(temp2);
                } catch (Exception e) {

                }
            }
            limsBarCodeDTO.setBarCodeSize(barCodeSize);
            barCodeDTOList.add(limsBarCodeDTO);
        }

        sampleTagDTO.setLimsBarCodeDTOList(barCodeDTOList);
        return sampleTagDTO;
    }

    @Override
    public Page<LimsSampleBean> selectSampleHandlesPagination(RestJsonWrapperBean wrapper) {
        return selectPagination(() -> getDao().selectSampleHandlesPagination(wrapper.extractMapFilter()), wrapper.extractPageRowBounds());
    }

    @Override
    public Long scanCodeCheck(RestJsonWrapperBean wrapper) {
        return relationService.scanCodeCheck(wrapper);
    }

/*    @Override
    @Transactional
    public void receiveSubmit(RestJsonWrapperBean wrapperBean) {
        List<LimsSampleBean> parse = wrapperBean.parse(LimsSampleBean.class);

        List<Long> batchSampleIds = parse.stream().map(s -> Long.parseLong(s.getExt$Item("batchSampleId"))).collect(Collectors.toList());
        List<LimsBatchSampleProductBean> productBeanAll = sampleProductService.selectListByFilter(SearchFilter.instance().match("batchSampleId", batchSampleIds).filter(MatchPattern.OR));
        List<LimsProductMainBean> mainBeans = limsProductMainService.selectListByIds(productBeanAll.stream().map(LimsBatchSampleProductBean::getProductId).distinct().collect(Collectors.toList()));
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter ymd = DateTimeFormatter.ofPattern("yyyyMMdd");
        List<String> dayOffs = coreCalendarService.selectListByFilter(SearchFilter.instance().match("workday", "0").filter(MatchPattern.EQ), Order.asc("id")).stream().map(CoreCalendarBean::getId).collect(Collectors.toList());
        logger.info("dayOffs----size{}", dayOffs.size());
        parse.forEach(s -> {
            if (s.getReceiveStatus().equals("normal")) {
                s.setStatus("inExperiment");
                s.setInHandle("1");
//                s.setHandleType("enterDone");
                s.setHandleType("wait");
                s.setInStoreTime(now);
            } else if (s.getReceiveStatus().equals("abnormal")) {
                s.setStatus("abnormal");
                s.setInStoreTime(now);
            }

            Long batchSampleId = Long.parseLong(s.getExt$Item("batchSampleId"));
            productBeanAll.stream().filter(p -> p.getBatchSampleId().equals(batchSampleId)).forEach(p -> {
                p.setStatus(s.getStatus());
                mainBeans.stream().filter(mp -> mp.getId().equals(p.getProductId())).findAny().ifPresent(mp -> {
                    if (!StringUtils.isBlank(mp.getStandardCycle())) {
                        try {
                            int cycle = Integer.parseInt(mp.getStandardCycle());
                            LocalDateTime total = now;
                            int dayNum = cycle / 24;
                            int hourNum = cycle % 24;
                            // 先把小时加上
                            total = total.plusHours(hourNum);
                            String date = total.format(ymd);
                            while (dayOffs.contains(date)) {
                                total = total.plusDays(1L);
                                date = total.format(ymd);
                            }
                            for (int i = 0; i < dayNum; i++) {
                                total = total.plusDays(1L);
                                date = total.format(ymd);
                                while (dayOffs.contains(date)) {
                                    total = total.plusDays(1L);
                                    date = total.format(ymd);
                                }
                            }
                            p.setPredictDeliveryTime(total);
                        } catch (Exception e) {

                        }
                    }
                });
            });
        });

        sampleProductService.getDao().fastUpdate(productBeanAll, "status", "predictDeliveryTime");
        getDao().fastUpdate(parse, "status", "inHandle", "handleType", "inStoreTime");

        List<Long> idList = parse.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.SAMPLE_RECEIVE"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

        List<LimsSampleBean> sampleBeans = parse.stream().filter(s -> s.getStatus().equals("inExperiment")
                && "TJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
        List<LimsSampleBean> pjSampleBeans = parse.stream().filter(s -> s.getStatus().equals("inExperiment")
                && "PJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
        // 进入实验的生成 PreFolder
        preFolderService.insertPreFolders(sampleBeans); // 特检
        pjFolderService.insertPjFolders(pjSampleBeans); // 普检
    }*/

    @Override
    @Transactional
    public void receiveSubmit(RestJsonWrapperBean wrapperBean) {
        List<LimsSampleBean> from = wrapperBean.parse(LimsSampleBean.class);
        if (from.isEmpty()) {
            return;
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        GikamConcurrentLocker.block(LocalDateTime.now().format(df));

        List<Long> batchSampleIds = from.stream().map(s -> Long.parseLong(s.getExt$Item("batchSampleId"))).collect(Collectors.toList());
        MapperParameter parameter = new MapperParameter();
        parameter.setFilter(SearchFilter.instance().match("BATCHSAMPLEID", batchSampleIds).filter(MatchPattern.OR).match("status", "receive").filter(MatchPattern.EQ));
        List<LimsSampleBean> finalParse = limsBatchSampleService.selectBatchSample(parameter);
        if (finalParse.isEmpty()) {
            return;
        }

        LocalDateTime now = LocalDateTime.now();
        finalParse.forEach(s -> {
            s.setInStoreTime(now);
            if (s.getReceiveStatus().equals("normal")) {
                s.setStatus("inExperiment");
                s.setInHandle("1");
//                s.setHandleType("enterDone");
                s.setHandleType("wait");
            } else if (s.getReceiveStatus().equals("abnormal")) {
                s.setStatus("abnormal");
            }
        });
        getDao().fastUpdate(finalParse, "status", "inHandle", "handleType", "inStoreTime");

        ExecutorHelper.submit(() -> setPredictDeliveryTime(finalParse));

        List<Long> idList = finalParse.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.SAMPLE_RECEIVE"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

        List<LimsSampleBean> sampleBeans = finalParse.stream().filter(s -> s.getStatus().equals("inExperiment")
                && "TJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
        List<LimsSampleBean> pjSampleBeans = finalParse.stream().filter(s -> s.getStatus().equals("inExperiment")
                && "PJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
        // 进入实验的生成 PreFolder
        preFolderService.insertPreFolders(sampleBeans); // 特检
        pjFolderService.insertPjFolders(pjSampleBeans); // 普检
    }

    // 设置交付时间
    private void setPredictDeliveryTime(List<LimsSampleBean> parse) {
        List<Long> batchSampleIds = parse.stream().map(s -> Long.parseLong(s.getExt$Item("batchSampleId"))).collect(Collectors.toList());
        List<LimsBatchSampleProductBean> productBeanAll = sampleProductService.selectListByFilter(SearchFilter.instance().match("batchSampleId", batchSampleIds).filter(MatchPattern.OR));
        List<LimsProductMainBean> mainBeans = limsProductMainService.selectListByIds(productBeanAll.stream().map(LimsBatchSampleProductBean::getProductId).distinct().collect(Collectors.toList()));
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter ymd = DateTimeFormatter.ofPattern("yyyyMMdd");
        List<String> dayOffs = coreCalendarService.selectListByFilter(SearchFilter.instance().match("workday", "0").filter(MatchPattern.EQ), Order.asc("id")).stream().map(CoreCalendarBean::getId).collect(Collectors.toList());
        logger.info("dayOffs----size{}", dayOffs.size());
        parse.forEach(s -> {
            Long batchSampleId = Long.parseLong(s.getExt$Item("batchSampleId"));
            productBeanAll.stream().filter(p -> p.getBatchSampleId().equals(batchSampleId)).forEach(p -> {
                p.setStatus(s.getStatus());
                mainBeans.stream().filter(mp -> mp.getId().equals(p.getProductId())).findAny().ifPresent(mp -> {
                    if (!StringUtils.isBlank(mp.getStandardCycle())) {
                        try {
                            long cycle = Long.parseLong(mp.getStandardCycle());
                            LocalDateTime total = now;
                            long dayNum = cycle / 24L;
                            long hourNum = cycle % 24;
                            // 先把小时加上
                            total = total.plusHours(hourNum);
                            String date = total.format(ymd);
                            while (dayOffs.contains(date)) {
                                total = total.plusDays(1L);
                                date = total.format(ymd);
                            }
                            for (int i = 0; i < dayNum; i++) {
                                total = total.plusDays(1L);
                                date = total.format(ymd);
                                while (dayOffs.contains(date)) {
                                    total = total.plusDays(1L);
                                    date = total.format(ymd);
                                }
                            }
                            p.setPredictDeliveryTime(total);
                        } catch (Exception e) {

                        }
                    }
                });
            });
        });

        sampleProductService.getDao().fastUpdate(productBeanAll, "status", "predictDeliveryTime");
    }

    @Override
    @Transactional
    public void abnormalSubmit(RestJsonWrapperBean wrapperBean) {
        List<LimsSampleBean> parse = wrapperBean.parse(LimsSampleBean.class);

        List<Long> batchSampleIds = parse.stream().map(s -> Long.parseLong(s.getExt$Item("batchSampleId"))).collect(Collectors.toList());
        List<LimsBatchSampleProductBean> productBeanAll = sampleProductService.selectListByFilter(SearchFilter.instance().match("batchSampleId", batchSampleIds).filter(MatchPattern.OR));

        parse.forEach(s -> s.setStatus("abnormalConfirm"));
        getDao().update(parse, "status");
        productBeanAll.forEach(p -> p.setStatus("abnormalConfirm"));
        sampleProductService.getDao().update(productBeanAll, "status");

        List<Long> idList = parse.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.SAMPLE_ABNORMAL"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

    }

    @Override
    @Transactional
    public void abnormalConfirm(RestJsonWrapperBean wrapperBean) {
        List<LimsSampleBean> parse = wrapperBean.parse(LimsSampleBean.class);
        List<LimsSampleBean> sampleBeans = new ArrayList<>();
        List<Long> batchSampleIdList = parse.stream().map(s -> Long.parseLong(s.getExt$Item("batchSampleId"))).distinct().collect(Collectors.toList());
        List<LimsBatchSampleProductBean> productBeans = sampleProductService.getDao().selectListByOneColumnValues(batchSampleIdList, "batchSampleId");
        parse.forEach(s -> {
            if ("stop".equals(s.getAbnormalHandleType())) {
                s.setStatus("stop");
                s.setHandleType("enterStop");
            } else {
                s.setStatus("inExperiment");
                s.setInHandle("1");
//                s.setHandleType("enterDone");
                s.setHandleType("wait");
                sampleBeans.add(s);
            }
            productBeans.stream().filter(p -> p.getBatchSampleId().equals(Long.parseLong(s.getExt$Item("batchSampleId"))))
                    .forEach(e -> e.setStatus(s.getStatus()));
        });

        sampleProductService.getDao().fastUpdate(productBeans, "status");
        getDao().fastUpdate(parse, "status", "inHandle", "handleType");

        List<Long> idList = parse.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.SAMPLE_ABNORMAL_CONFIRM"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

        List<LimsSampleBean> tjSampleBeans = sampleBeans.stream().filter(s ->
                "TJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
        List<LimsSampleBean> pjSampleBeans = sampleBeans.stream().filter(s ->
                "PJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
        // 进入实验的生成 PreFolder
        preFolderService.insertPreFolders(tjSampleBeans); // 特检
        pjFolderService.insertPjFolders(pjSampleBeans); // 普检
    }

    @Override
    public JSONObject uploadAttachmentMulti(RestJsonWrapperBean jsonWrapperBean) {
        JSONObject req = new JSONObject();

        String fileIdString = jsonWrapperBean.getParamValue("fileIds");
        List<Long> fileIds = Arrays.stream(fileIdString.split(",")).map(Long::parseLong).collect(Collectors.toList());
        List<CoreFileBean> fileBeans = coreFileService.selectListByFilter(SearchFilter.instance().match("id", fileIds).filter(MatchPattern.OR));
        List<LimsSampleBean> sampleBeans = jsonWrapperBean.parse(LimsSampleBean.class, 0);

        List<CoreFileBean> insertFiles = new ArrayList<>();
        List<CoreFileLogBean> uploadLogs = new ArrayList<>();
        fileBeans.forEach(f -> {
            FilePathDTO filePathDTO = CoreFileUtils.toFilePath(f);
            Path path = FilePathManager.getLocalPath(filePathDTO);
            File uploadFile = path.toFile();
            coreFileManager.download(f);
            for (LimsSampleBean s : sampleBeans) {
                if (!f.getTargetId().contains(s.getId().toString())) {
                    CoreFileBean insertCoreFile = new CoreFileBean();
                    insertCoreFile.setTargetId("T_LIMS_SAMPLE$" + s.getId());
                    Long key = ApplicationContextHelper.getNextIdentity();
                    insertCoreFile.setId(key);
                    insertCoreFile.setName(uploadFile.getName());
                    insertCoreFile.setFileExt(com.sunwayworld.framework.utils.FileUtils.getFileExtension(uploadFile.getName()));
                    insertCoreFile.setMd5Name(EncryptUtils.MD5Encrypt(key + "$" + uploadFile.getName()));
                    insertCoreFile.setScope(Objects.toString(f.getScope(), FileScope.secure.name()));
                    insertCoreFile.setValidTimeFrom(f.getValidTimeFrom());
                    insertCoreFile.setValidTimeTo(f.getValidTimeTo());
                    insertCoreFile.setSize(uploadFile.length());
                    insertCoreFile.setTimes(0L);
                    insertCoreFile.setExt(f.getExt());
                    insertCoreFile.setDownloadable("1");
                    insertCoreFile.setCreatedTime(LocalDateTime.now());
                    insertCoreFile.setExt$(f.getExt$());
                    insertCoreFile.setBizCategory(f.getBizCategory());
                    insertFiles.add(insertCoreFile);
                    coreFileManager.upload(insertCoreFile, uploadFile);

                    CoreFileLogBean uploadLog = new CoreFileLogBean();
                    uploadLog.setFileId(insertCoreFile.getId());
                    uploadLog.setId(ApplicationContextHelper.getNextIdentity());
                    uploadLog.setCreatedTime(insertCoreFile.getCreatedTime());
                    uploadLog.setOperationCategory("INSERT");
                    uploadLogs.add(uploadLog);
                }
            }
        });
        if (!insertFiles.isEmpty()) {
            coreFileService.getDao().insert(insertFiles);
        }
        if (!uploadLogs.isEmpty()) {
            coreFileLogService.getDao().insert(uploadLogs);
        }
        return req;
    }

    @Override
    public JSONObject getCourierData(RestJsonWrapperBean jsonWrapperBean) {
        return limsCourierService.getCourierData(jsonWrapperBean);
    }

    @Override
    public List<BatchSampleStaticsDTO> selectBatchSampleStaticsPage(String year) {
        //BatchSampleStaticsDTO sampleStaticsDTO=jsonWrapperBean.parseUnique(BatchSampleStaticsDTO.class);
        //String year = jsonWrapperBean.getParamValue("year");
/*        List<Map<String, Object>> mapList = getDao().selectBatchCountStatics(year, LocalContextHelper.getLoginOrgId());
        List<Map<String, Object>> mapList1 = getDao().selectSampleCountStatics(year, LocalContextHelper.getLoginOrgId());
        List<BatchSampleStaticsDTO> sampleBeans = new ArrayList<>();

        if (!mapList.isEmpty() && mapList.size() > 0) {
            sampleBeans.addAll(mapList.stream().map(m -> PersistableHelper.mapToPersistable(m, BatchSampleStaticsDTO.class)).collect(Collectors.toList()));
        }
        if (!mapList1.isEmpty() && mapList1.size() > 0) {
            sampleBeans.addAll(mapList1.stream().map(m -> PersistableHelper.mapToPersistable(m, BatchSampleStaticsDTO.class)).collect(Collectors.toList()));
        }*/

        List<Map<String, Object>> mapList = getDao().selectBatchCountStatics(year, LocalContextHelper.getLoginOrgId());
        List<Map<String, Object>> mapList1 = getDao().selectSampleCountStatics(year, LocalContextHelper.getLoginOrgId());
        List<BatchSampleStaticsDTO> sampleBeans = new ArrayList<>();

        List<BatchSampleStaticsDTO> batchData = mapList.stream().map(m -> PersistableHelper.mapToPersistable(m, BatchSampleStaticsDTO.class)).collect(Collectors.toList());
        List<BatchSampleStaticsDTO> sampleData = mapList1.stream().map(m -> PersistableHelper.mapToPersistable(m, BatchSampleStaticsDTO.class)).collect(Collectors.toList());
        for (int i = 1; i <= 12; i++) {
            String month = String.format("%02d", i);
            Optional<BatchSampleStaticsDTO> optional = batchData.stream().filter(b -> b.getMonth().equals(month)).findFirst();
            if (optional.isPresent()) {
                sampleBeans.add(optional.get());
            } else {
                sampleBeans.add(new BatchSampleStaticsDTO(year, month, "batch"));
            }
        }
        for (int i = 1; i <= 12; i++) {
            String month = String.format("%02d", i);
            Optional<BatchSampleStaticsDTO> optional = sampleData.stream().filter(b -> b.getMonth().equals(month)).findFirst();
            if (optional.isPresent()) {
                sampleBeans.add(optional.get());
            } else {
                sampleBeans.add(new BatchSampleStaticsDTO(year, month, "sample"));
            }
        }

        return sampleBeans;
    }

    @Override
    public List<LimsSampleBean> selectSampleHandlesList(MapperParameter parameter) {
        return getDao().selectSampleHandlesPagination(parameter).parallelStream().map(m -> PersistableHelper.mapToPersistable(m, LimsSampleBean.class)).collect(Collectors.toList());
    }

    @Override
    public List<LimsSampleBean> selectListByParams(MapperParameter parameter) {
        return getDao().selectByParams(parameter).parallelStream().map(s -> PersistableHelper.mapToPersistable(s, LimsSampleBean.class)).collect(Collectors.toList());
    }

    @Override
    /*
     * 追溯
     * */
    public List<SampleTreeDTO> selectTree(MapperParameter parameter) {
        String sampleIdStr = parameter.get("sampleIds").toString();
        if (StringUtils.isEmpty(sampleIdStr)) {
            return CollectionUtils.emptyList();
        }
        List<Long> oriIdList = new ArrayList<>();
        List<String> oriNoList = new ArrayList<>();

        List<Long> sampleIdList = Arrays.stream(StringUtils.split(sampleIdStr, ",")).map(NumberUtils::parseLong).collect(Collectors.toList());
        List<LimsSampleDerivativeBean> sampleDerivativeBeanList = sampleDerivativeService.selectListByFilter(SearchFilter.instance().match("derivativeId", sampleIdList).filter(MatchPattern.OR));
        if (sampleDerivativeBeanList.isEmpty()) {
            oriIdList.addAll(sampleIdList);
        } else {
            sampleDerivativeBeanList.forEach(m -> oriNoList.addAll(ArrayUtils.asList(StringUtils.split(m.getOriNo(), ","))));
            MapperParameter temp = new MapperParameter();
            temp.setFilter(SearchFilter.instance().match("sampleCode", oriNoList.stream().distinct().collect(Collectors.toList())).filter(MatchPattern.OR));
            List<LimsSampleBean> sampleBeanList = this.selectSampleList(temp);
            temp.clear();
            if (!sampleBeanList.isEmpty()) {//衍生物原始样本Id
                oriIdList.addAll(sampleBeanList.stream().map(LimsSampleBean::getId).collect(Collectors.toList()));
            }
            List<Long> ornIds = sampleDerivativeBeanList.stream().map(LimsSampleDerivativeBean::getDerivativeId).distinct().collect(Collectors.toList());
            sampleIdList.removeAll(ornIds);
            if (!CollectionUtils.isEmpty(sampleIdList)) {//原始样本Id
                oriIdList.addAll(sampleIdList);
            }
        }
        if (oriIdList.isEmpty()) {
            return CollectionUtils.emptyList();
        }
        parameter.put("sampleIdList", StringUtils.join(oriIdList, ","));
        List<Map<String, Object>> childrenMap = getDao().selectSampleChildren(parameter);
        List<LimsSampleBean> sampleList = getDao().selectListByIds(oriIdList);
        sampleList.addAll(childrenMap.stream().map(m -> PersistableHelper.mapToPersistable(m, LimsSampleBean.class)).collect(Collectors.toList()));
        TreeDescriptor<LimsSampleBean> descriptor = new TreeDescriptor<>("id", "sampleCode");
        descriptor.setParseTreeNodeParentIdFunc(sample -> sample.getExt$Item("parentId"));
        return TreeHelper.parseTreeNode(sampleList, descriptor, SampleTreeDTO.class);
    }

    @Override
    public List<LimsSampleBean> selectSampleList(MapperParameter temp) {
        List<Map<String, Object>> mapList = getDao().selectBatchSample(temp);
        if (mapList.isEmpty()) {
            return new ArrayList<>();
        }
        List<LimsSampleBean> sampleBeans = mapList.stream().map(m -> PersistableHelper.mapToPersistable(m, LimsSampleBean.class)).collect(Collectors.toList());
        return sampleBeans;
    }

    @Override
    public Page<LimsSampleBean> selectTestMethodBySampleCode(RestJsonWrapperBean wrapper) {
        return selectPagination(() -> getDao().selectTestMethodBySampleCode(wrapper.extractMapFilter()), wrapper.extractPageRowBounds());
    }

    @Override
    public Page<LimsSampleBean> selectBatchChooseSamplePagination(RestJsonWrapperBean wrapper) {
        return selectPagination(() -> getDao().selectBatchChooseSample(wrapper.extractMapFilter()), wrapper.extractPageRowBounds());
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.UPDATE)
    public Long print(RestJsonWrapperBean wrapper) {
        Long fileId = null;
        List<LimsSampleBean> limsSampleBeans = wrapper.parse(LimsSampleBean.class);
        if (!limsSampleBeans.isEmpty()) {
            List<Long> ids = limsSampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
            limsSampleBeans = this.selectListByFilter(SearchFilter.instance().match("id", ids).filter(MatchPattern.OR));
            // 查询标签模板
            List<LimsExportTemplateBean> limsExportTemplateBeans = exportTemplateService.selectListByFilter(SearchFilter.instance().match("templateCode", "SampleCodePrintTemplate").filter(MatchPattern.EQ));

            if (!limsExportTemplateBeans.isEmpty()) {
                CoreFileBean template = coreFileService.selectById(limsExportTemplateBeans.get(0).getTemplateFileId());
                FilePathDTO fr = CoreFileUtils.toFilePath(template);

                String templatePath = FilePathManager.getLocalPath(fr).toString();
                logger.info("templatePath----".concat(templatePath));
                if (StringUtils.isBlank(templatePath)) {
                    throw new InvalidDataException("LIMS.BUSINESS.REPORT.ALERT.NO_TEMPLATE");
                }
                coreFileManager.download(template, FilePathManager.getLocalPath(fr));
                // 填充模板，生成文件
                try (InputStream templateFile = new FileInputStream(templatePath); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                    List<LimsSampleBean> finalLimsSampleBeans = limsSampleBeans;
                    ExportUtil.build(templateFile, builder -> this.buildSampleTagParams2(builder, finalLimsSampleBeans), os);

                    // 生成的文件导入到系统
                    fileId = ApplicationContextHelper.getNextIdentity();
                    CoreFileBean insertCoreFile = new CoreFileBean();
                    insertCoreFile.setId(fileId);
                    insertCoreFile.setTargetId("T_LIMS_SAMPLE_BARCODE" + "$" + StringUtils.randomUUID());//分类报告
                    insertCoreFile.setName("样本标签.docx");
                    insertCoreFile.setFileExt(FileUtils.getFileExtension(insertCoreFile.getName()));
                    insertCoreFile.setMd5Name(EncryptUtils.MD5Encrypt(fileId + "$" + insertCoreFile.getName()));
                    insertCoreFile.setScope(FileScope.secure.name());
                    insertCoreFile.setSize((long) os.size());
                    insertCoreFile.setTimes(0L);
                    insertCoreFile.setExt("docx");
                    insertCoreFile.setDownloadable("1");
                    insertCoreFile.setCreatedTime(LocalDateTime.now());
                    coreFileService.getDao().insert(insertCoreFile);
                    //downloadUrl = coreFileManager.getAbsoluteDownloadUrl(insertCoreFile.getId());

                    try (ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray())) {
                        coreFileManager.upload(insertCoreFile, in);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return fileId;
    }

    /**
     * *********************************************************************************
     * 构建word需要的参数
     *
     * @param configureBuilder 构建配置
     * @return word参数
     */
    private LimsSampleTagDTO buildSampleTagParams2(ConfigureBuilder configureBuilder, List<LimsSampleBean> limsSampleBeans) {
        LimsSampleTagDTO limsSampleTagDTO = new LimsSampleTagDTO();
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        List<LimsBarCodeDTO> limsBarCodeDTOList = new ArrayList<LimsBarCodeDTO>();
        int qrCodeSize = 400;
        String temp = ApplicationContextHelper.getConstantValue("qrCodeSize");
        if (!StringUtils.isBlank(temp)) {
            try {
                qrCodeSize = Integer.parseInt(temp);
            } catch (Exception e) {

            }
        }
        for (LimsSampleBean limsSampleBean : limsSampleBeans) {
            LimsBarCodeDTO limsBarCodeDTO = new LimsBarCodeDTO();
            limsBarCodeDTO.setSampleCode(limsSampleBean.getSampleCode());
            limsBarCodeDTO.setSampleName(limsSampleBean.getSampleName());
            limsBarCodeDTO.setBatchCode(limsSampleBean.getExt$Item("BATCHCODE"));
            limsBarCodeDTO.setBoard(limsSampleBean.getLocations());
            limsBarCodeDTO.setBarcode(zxingCodeCreate(limsSampleBean.getSampleCode(), qrCodeSize, qrCodeSize));
            limsBarCodeDTO.setDate(date);

            limsBarCodeDTO.setCodeFront(limsSampleBean.getSampleCode().substring(0, limsSampleBean.getSampleCode().length() / 2));
            limsBarCodeDTO.setCodeBack(limsSampleBean.getSampleCode().substring(limsSampleBean.getSampleCode().length() / 2));
            int barCodeSize = 50;
            String temp2 = ApplicationContextHelper.getConstantValue("barCodeSize");
            if (!StringUtils.isBlank(temp2)) {
                try {
                    barCodeSize = Integer.parseInt(temp2);
                } catch (Exception e) {

                }
            }
            limsBarCodeDTO.setBarCodeSize(barCodeSize);
            limsBarCodeDTOList.add(limsBarCodeDTO);
        }
        limsSampleTagDTO.setLimsBarCodeDTOList(limsBarCodeDTOList);
        return limsSampleTagDTO;
    }

    /**
     * 生成二维码
     *
     * @param text   二维码内容
     * @param width  二维码宽
     * @param height 二维码高
     */
    public static byte[] zxingCodeCreate(String text, int width, int height) {
        Map<EncodeHintType, String> his = new HashMap<EncodeHintType, String>();
        // 设置编码字符集
        his.put(EncodeHintType.CHARACTER_SET, "utf-8");
        try {
            // 1、生成二维码
            BitMatrix encode = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, his);

            // 2、获取二维码宽高
            int codeWidth = encode.getWidth();
            int codeHeight = encode.getHeight();

            // 3、将二维码放入缓冲流
            BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);
            for (int i = 0; i < codeWidth; i++) {
                for (int j = 0; j < codeHeight; j++) {
                    // 4、循环将二维码内容定入图片
                    image.setRGB(i, j, encode.get(i, j) ? BLACK : WHITE);
                }
            }
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", out);
            return out.toByteArray();
        } catch (WriterException e) {
            e.printStackTrace();
            System.out.println("二维码生成失败");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("生成二维码图片失败");
        }
        return null;
    }

    @Override
    public RestValidationResultBean validateGeneratedSamplecode(Long id, String columnName, String columnValue) {
        Map<String, Object> columnMap = new CaseInsensitiveLinkedMap();
        columnMap.put(columnName, columnValue);
        return this.validateGeneratedSamplecode(id, columnMap);
    }

    public RestValidationResultBean validateGeneratedSamplecode(Long id, Map<String, Object> columnMap) {
        LimsSampleBean searchTerms;
        if (columnMap == null || columnMap.isEmpty() || columnMap.size() == 1 && columnMap.containsKey("ID") || columnMap.size() == 1 && columnMap.containsKey(null)) {
            searchTerms = this.getDao().selectByIdIfPresent(id);
            return searchTerms == null ? new RestValidationResultBean(true) : new RestValidationResultBean(false, "core.validator.column.not-unique");
        } else {
            searchTerms = ClassUtils.newInstance(LimsSampleBean.class);
            columnMap.forEach((k, v) -> {
                BeanPropertyDescriptor propertyDescriptor = BeanPropertyHelper.getBeanPropertyDescriptor(LimsSampleBean.class, k);
                if (propertyDescriptor == null) {
                    searchTerms.setExt$Item(k, v == null ? null : v.toString());
                } else {
                    ReflectionUtils.invokeMethod(propertyDescriptor.getWriteMethod(), searchTerms, ConvertUtils.convert(v, propertyDescriptor.getPropertyType()));
                }
            });

            LimsSamplecodeGenerateRecordBean limsSamplecodeGenerateRecordBean = limsSamplecodeGenerateRecordService.selectFirstByFilter(SearchFilter.instance().match("generateSampleCode", searchTerms.getSampleCode()).filter(MatchPattern.EQ));
            if (limsSamplecodeGenerateRecordBean == null) {
                return new RestValidationResultBean(false, "请使用系统生成的样本编号");
            } else {
                List<Long> idList = this.getDao().selectColumnList(searchTerms, "ID", Long.class);
                if (idList.isEmpty()) {
                    return new RestValidationResultBean(true);
                } else if (idList.size() > 1) {
                    return new RestValidationResultBean(false, "core.validator.column.not-unique");
                } else {
                    return !((Serializable) idList.get(0)).equals(id) ? new RestValidationResultBean(false, "core.validator.column.not-unique") : new RestValidationResultBean(true);
                }
            }
        }
    }

    @Override
    public Page<LimsSampleBean> selectPassRate(RestJsonWrapperBean wrapper) {
        return selectPagination(() -> getDao().selectPassRate(wrapper.extractMapFilter()), wrapper.extractPageRowBounds());
    }
}
